package online.chazi.netkit;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleState;
import lombok.extern.slf4j.Slf4j;
import online.chazi.netkit.channel.NetkitPipelineFactory;

/**
 * 说明：作者很懒，什么都没留下
 * Created by 叉子同学 on 2020-04-24 17:15
 */
@Slf4j
public class NetkitClient {

    private final NetkitContext context;
    private String host;
    private int port;

    private Bootstrap bootstrap;
    private EventLoopGroup workerGroup = new NioEventLoopGroup();

    public NetkitClient(NetkitContext context, String host, int port) {
        this.context = context;
        //客户端默认要主动发送心跳
        this.context.setSessionIdleState(IdleState.WRITER_IDLE);
        this.host = host;
        this.port = port;
        bootstrap = new Bootstrap()
                .group(workerGroup)
                .channel(NioSocketChannel.class)
                .handler(new NetkitPipelineFactory(context));
    }

    public Session createSession() throws Exception {
        ChannelFuture future = this.bootstrap.connect(host, port).sync();
        NetkitClient.CreateSessionSuccessListener success = new NetkitClient.CreateSessionSuccessListener();
        future.addListener(success);
        return success.getSession();
    }

    public void close() {
        this.context.release();
        this.workerGroup.shutdownGracefully();
    }

    class CreateSessionSuccessListener implements ChannelFutureListener {

        private final Object lock = new Object();
        private Session session;

        CreateSessionSuccessListener() {
        }

        public void operationComplete(ChannelFuture future) throws Exception {
            try {
                this.session = NetkitClient.this.context.createSession(future.channel());
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            synchronized (this.lock) {
                this.lock.notifyAll();
            }
        }

        public Session getSession() throws InterruptedException {
            this.join();
            return this.session;
        }

        private void join() throws InterruptedException {
            synchronized (this.lock) {
                while (this.session == null) {
                    this.lock.wait();
                }
            }
        }

    }

}
